/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package es.udc.emarketapp.http.controller.session;

import es.udc.emarketapp.emarket.model.usersFacade.UsersFacade;
import es.udc.emarketapp.emarket.model.usersFacade.exceptions.IncorrectPasswordException;
import es.udc.emarketapp.emarket.model.usersFacade.vo.LoginResultVO;
import es.udc.fbellas.j2ee.util.exceptions.InstanceNotFoundException;
import es.udc.fbellas.j2ee.util.exceptions.InternalErrorException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 *
 * @author martin
 */
public final class SessionManager {

    public final static String ID_USER_SESSION_ATTRIBUTE = "idUser";
    public final static String TYPE_SESSION_ATTRIBUTE = "type";
    private final static String USERS_FACADE_SESSION_ATTRIBUTE = "usersFacade";
    public static final String LOGIN_NAME_COOKIE = "loginName";
    public static final String ENCRYPTED_PASSWORD_COOKIE = "encryptedPassword";
    public static final String ADMIN = "ADMIN";
    public static final String SELLER = "SELLER";
    public static final String CLIENT = "CLIENT";
    private static final int COOKIES_TIME_TO_LIVE_REMEMBER_MY_PASSWORD =
            30 * 24 * 3600; // 30 days
    private static final int COOKIES_TIME_TO_LIVE_REMOVE = 0;

    private SessionManager() {
    }

    public final static void login(HttpServletRequest request,
            HttpServletResponse response, String loginName,
            String clearPassword, boolean rememberMyPassword, boolean isAdmin)
            throws IncorrectPasswordException,
            InstanceNotFoundException, InternalErrorException {

        /*
         * Try to login, and if successful, update session with the necessary
         * objects for an authenticated user.
         */
        LoginResultVO loginResultVO =
                doLogin(request, loginName, clearPassword, false, isAdmin);


        /* Add cookies if requested. */
        if (rememberMyPassword) {
            leaveCookies(response, loginName,
                    loginResultVO.getEncryptedPassword(),
                    COOKIES_TIME_TO_LIVE_REMEMBER_MY_PASSWORD);
        }

    }

    public final static void logout(HttpServletRequest request,
            HttpServletResponse response) throws InternalErrorException {

        /* Remove cookies. */
        leaveCookies(response, "", "", COOKIES_TIME_TO_LIVE_REMOVE);

        /* Invalidate session. */
        HttpSession session = request.getSession(true);
        session.invalidate();

    }

    public final static String getIdUser(HttpServletRequest request) {

        HttpSession session = request.getSession(false);

        return (String) session.getAttribute(ID_USER_SESSION_ATTRIBUTE);
    }

    public final static UsersFacade getUsersFacade(
            HttpServletRequest request) throws InternalErrorException {

        HttpSession session = request.getSession(true);
        UsersFacade usersFacade = (UsersFacade) session.getAttribute(
                USERS_FACADE_SESSION_ATTRIBUTE);

        if (usersFacade == null) {
            usersFacade = new UsersFacade();
            session.setAttribute(USERS_FACADE_SESSION_ATTRIBUTE,
                    usersFacade);
        }

        return usersFacade;

    }

    /**
     * Guarantees that the session will have the necessary objects if the user
     * has been authenticated or had selected "remember my password" in the
     * past.
     */
    public final static void touchSession(HttpServletRequest request)
            throws InternalErrorException {

        /* Check if "firstName" is in the session. */
        String idUser = null;
        HttpSession session = request.getSession(false);

        if (session != null) {
            idUser = (String) session.getAttribute(
                    ID_USER_SESSION_ATTRIBUTE);

            if (idUser != null) {
                return;
            }
        }
        /*
         * The user had not been authenticated or his/her session has expired.
         * We need to check if the user has selected "remember my password" in
         * the last login (login name and password will come as cookies). If
         * so, we reconstruct user's session objects.
         */
        updateSessionFromCookies(request);

    }

    public final static boolean isUserAuthenticated(
            HttpServletRequest request) {

        HttpSession session = request.getSession(false);

        if (session == null) {
            return false;
        } else {
            return session.getAttribute(ID_USER_SESSION_ATTRIBUTE) != null;
        }

    }

    public final static boolean isAdmin(
            HttpServletRequest request) {

        HttpSession session = request.getSession(false);

        if (session == null) {
            return false;
        } else {
            return session.getAttribute(TYPE_SESSION_ATTRIBUTE).equals(ADMIN);
        }

    }

    public final static boolean isSeller(
            HttpServletRequest request) {

        HttpSession session = request.getSession(false);

        if (session == null) {
            return false;
        } else {
            return session.getAttribute(TYPE_SESSION_ATTRIBUTE).equals(SELLER);
        }
    }

    public final static boolean isClient(
            HttpServletRequest request) {

        HttpSession session = request.getSession(false);

        if (session == null) {
            return false;
        } else {
            return session.getAttribute(TYPE_SESSION_ATTRIBUTE).equals(CLIENT);
        }
    }

    private final static LoginResultVO doLogin(HttpServletRequest request,
            String loginName, String password, boolean passwordIsEncrypted,
            boolean isAdmin) throws IncorrectPasswordException,
            InstanceNotFoundException, InternalErrorException {

        /* Check "loginName" and "clearPassword". */
//        UsersManagementFacadeDelegate usersManagementFacadeDelegate =
//    			getUsersManagementFacadeDelegate(request);


        UsersFacade usersFacade = new UsersFacade();

        LoginResultVO loginResultVO = usersFacade.login(loginName, password,
                passwordIsEncrypted, isAdmin);


        /* Insert necessary objects in the session. */
        updateSessionForAuthenticatedUser(request, loginResultVO.getIdUser(),
                loginResultVO.getType());
        System.out.println(loginResultVO.toString());

        /* Return "loginResultVO". */
        return loginResultVO;

    }

    private final static void leaveCookies(HttpServletResponse response,
            String loginName, String encryptedPassword, int timeToLive) {

        /* Create cookies. */
        Cookie loginNameCookie = new Cookie(LOGIN_NAME_COOKIE, loginName);
        Cookie encryptedPasswordCookie = new Cookie(ENCRYPTED_PASSWORD_COOKIE,
                encryptedPassword);

        /* Set maximum age to cookies. */
        loginNameCookie.setMaxAge(timeToLive);
        encryptedPasswordCookie.setMaxAge(timeToLive);

        /* Add cookies to response. */
        response.addCookie(loginNameCookie);
        response.addCookie(encryptedPasswordCookie);

    }

    private final static void updateSessionForAuthenticatedUser(
            HttpServletRequest request, String idUser, String type)
            throws InternalErrorException {

        /* Insert objects in session. */
        HttpSession session = request.getSession(true);
        session.setAttribute(ID_USER_SESSION_ATTRIBUTE, idUser);
        session.setAttribute(TYPE_SESSION_ATTRIBUTE, type);
//        session.setAttribute(Globals.LOCALE_KEY, locale);
    }

    /**
     * Tries to login (inserting necessary objects in the session) by using
     * cookies (if present).
     */
    private final static void updateSessionFromCookies(
            HttpServletRequest request) throws InternalErrorException {

        /* Are there cookies in the request ? */
        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
            return;
        }

        /*
         * Check if the login name and the encrypted password come as
         * cookies.
         */
        String loginName = null;
        String encryptedPassword = null;
        int foundCookies = 0;

        for (int i = 0; (i < cookies.length) && (foundCookies < 2); i++) {
            if (cookies[i].getName().equals(LOGIN_NAME_COOKIE)) {
                loginName = cookies[i].getValue();
                foundCookies++;
            }
            if (cookies[i].getName().equals(ENCRYPTED_PASSWORD_COOKIE)) {
                encryptedPassword = cookies[i].getValue();
                foundCookies++;
            }
        }

        if (foundCookies != 2) {
            return;
        }

        /* Try to login, and if successful, update session with the necessary
         * objects for an authenticated user.
         */
        try {
            //if (loginName.compareTo("admin")!=0) {
            doLogin(request, loginName, encryptedPassword, true, true);
            //}
        } catch (InternalErrorException e) {
            throw e;
        } catch (Exception e) { // Incorrect loginName or encryptedPassword
            return;
        }
    }

    public final static void changePassword(HttpServletRequest request,
            HttpServletResponse response, String oldClearPassword,
            String newClearPassword) throws IncorrectPasswordException,
            InternalErrorException {

        /* Change user's password. */
        String idUser = getIdUser(request);

        UsersFacade usersFacade = getUsersFacade(request);

        usersFacade.changePassword(idUser, oldClearPassword, newClearPassword);

        /* Remove cookies. */
        leaveCookies(response, "", "", COOKIES_TIME_TO_LIVE_REMOVE);

    }
}
